package com.yusvn.scm.common;

import java.sql.Connection;
import java.sql.SQLException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.Date;

import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.wall.WallFilter;
import com.github.yitter.contract.IdGeneratorOptions;
import com.github.yitter.idgen.YitIdHelper;
import com.jfinal.config.Constants;
import com.jfinal.config.Handlers;
import com.jfinal.config.Interceptors;
import com.jfinal.config.JFinalConfig;
import com.jfinal.config.Plugins;
import com.jfinal.config.Routes;
import com.jfinal.ext.cors.CORSInterceptor;
import com.jfinal.json.MixedJsonFactory;
import com.jfinal.kit.Prop;
import com.jfinal.kit.PropKit;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.CaseInsensitiveContainerFactory;
import com.jfinal.plugin.activerecord.DbKit;
import com.jfinal.plugin.activerecord.dialect.OracleDialect;
import com.jfinal.plugin.druid.DruidPlugin;
import com.jfinal.server.undertow.UndertowServer;
import com.jfinal.template.Engine;
import com.yusvn.scm.common.constant.Const;
import com.yusvn.scm.common.interceptor.ExceptionInterceptor;
import com.yusvn.scm.common.kit.DruidKit;
import com.yusvn.scm.common.model._MappingKit;
import com.yusvn.scm.common.model._MappingKitScm;
import com.yusvn.scm.common.model._MappingKitScm1;
import com.yusvn.scm.common.routes.AdminRoutes;
import com.yusvn.scm.common.routes.BiRoutes;
import com.yusvn.scm.quartz.service.ScmJobService;

import cn.hutool.cron.CronUtil;

/**
 * 程序配置信息
 * @author liugz
 *
 */
public class AppConfig extends JFinalConfig {
	
	// 使用 jfinal-undertow 时此处仅保留声明，不能有加载代码
	private static Prop p;
	
	private WallFilter wallFilter;
	
	/**
	 * 启动入口，运行此 main 方法可以启动项目
	 */
	public static void main(String[] args) {
		UndertowServer.start(AppConfig.class);
	}
	
	/**
	 * PropKit.useFirstFound(...) 使用参数中从左到右最先被找到的配置文件
	 * 从左到右依次去找配置，找到则立即加载并立即返回，后续配置将被忽略
	 */
	static void loadConfig() {
		if (p == null) {
			p = PropKit.useFirstFound("app-config-pro.txt", "app-config-dev.txt");
		}
	}
	
	/**
	 * 配置常量
	 */
	@Override
	public void configConstant(Constants me) {
		loadConfig();
		
		//设置默认下载路径
		//me.setBaseDownloadPath("D:/ysscm/download");
		//me.setBaseUploadPath("D:/ysscm/upload");
		me.setMaxPostSize(1024 * 1024 * 50); //上传文件最大允许50M
		me.setDevMode(p.getBoolean("devMode", false));
		me.setJsonFactory(MixedJsonFactory.me());  //FastJsonFactory.me()  MixedJsonFactory.me()
		
		// 支持 Controller、Interceptor、Validator 之中使用 @Inject 注入业务层，并且自动实现 AOP
		me.setInjectDependency(true);
		
		// 上传文件的位置
		me.setBaseUploadPath("C:/Download");
		
		// 是否对超类中的属性进行注入
		me.setInjectSuperClass(true);
	}

	/**
	 * 配置路由
	 */
	@Override
	public void configRoute(Routes me) {
		me.add(new AdminRoutes());   //后台
		me.add(new BiRoutes());   //BI报表
		//me.add(new TestRoutes());    //测试		
	}

	/**
	 * 配置模板引擎
	 */
	@Override
	public void configEngine(Engine me) {
		me.setDevMode(p.getBoolean("engineDevMode", false));
		
	}

	/**
	 * 数据连接，抽取成独立的方法，便于 _Generator.java 中重用该方法，减少代码冗余
	 */
	public static DruidPlugin getDruidPlugin() {
		loadConfig();
		//mysql5 com.mysql.jdbc.Driver
		//return new DruidPlugin(p.get("jdbcUrl"), p.get("user"), p.get("password"));
		
		//mysql8 com.mysql.cj.jdbc.Driver
		return new DruidPlugin(p.get("jdbcUrl"), p.get("user"), p.get("password"), p.get("driverClass"));
	}

	/**
	 * 客户业务数据连接，抽取成独立的方法，便于 _Generator.java 中重用该方法，减少代码冗余
	 */
	public static DruidPlugin getDruidPluginScm() {
		loadConfig();
		return new DruidPlugin(p.get("jdbcUrlScm"), p.get("userScm"), p.get("passwordScm"), p.get("driverClassScm"));
	}
	
	/**
	 * scm业务
	 */
	public static DruidPlugin getDruidPluginScm1() {
		loadConfig();
		return new DruidPlugin(p.get("jdbcUrlScm1"), p.get("userScm1"), p.get("passwordScm1"), p.get("driverClassScm1"));
	}
	
	
	/**
	 * 配置插件
	 */
	@Override
	public void configPlugin(Plugins me) {
		DruidPlugin druidPlugin = getDruidPlugin();
		wallFilter = new WallFilter();			// 加强数据库安全
		wallFilter.setDbType("mysql");
		druidPlugin.addFilter(wallFilter);
		druidPlugin.addFilter(new StatFilter());	// 添加 StatFilter 才会有统计数据
		me.add(druidPlugin);
		
		ActiveRecordPlugin arp = new ActiveRecordPlugin(druidPlugin);
		arp.setTransactionLevel(Connection.TRANSACTION_READ_COMMITTED);
		_MappingKit.mapping(arp);
		me.add(arp);
		arp.setShowSql(p.getBoolean("showSql", false));

		arp.getEngine().setToClassPathSourceFactory();
		
		//getSqlTemplate(PathKit.getRootClassPath() + "/template",  arp); //扫描sql模板
		arp.addSqlTemplate("/sql/admin/_all_sqls_admin.sql");
		
		
		//客户业务数据库
		DruidPlugin druidPluginScm = getDruidPluginScm(); //new DruidPlugin(p.get("jdbcUrlScm"), p.get("userScm"), p.get("passwordScm"), p.get("driverClassScm"));
		druidPluginScm.setMaxPoolPreparedStatementPerConnectionSize(50); //
		//druidPluginScm.setRemoveAbandonedTimeoutMillis(360*1000);
		me.add(druidPluginScm);
		
		ActiveRecordPlugin arpScm = new ActiveRecordPlugin(Const.SCMDB, druidPluginScm);
		arpScm.setDialect(new OracleDialect()); // 配置sqlserver方言
		arpScm.setContainerFactory(new CaseInsensitiveContainerFactory(true)); // 配置属性名(字段名)大小写不敏感容器工厂,true小写,false大写
		_MappingKitScm.mapping(arpScm);
		me.add(arpScm);
		arpScm.setShowSql(p.getBoolean("showSql", true));

		arpScm.getEngine().setToClassPathSourceFactory();
		
		arpScm.addSqlTemplate("/sql/base/_all_sqls_base.sql"); //基础数据
		
		
		//设置模板引擎的共享方法，可以放到sql模板和页面中像java中一样使用StrKit方法
		arpScm.getSqlKit().getEngine().addSharedObject("StrKit", new com.jfinal.kit.StrKit());
		
		//客户业务数据库
		DruidPlugin druidPluginScm1 = getDruidPluginScm1(); 
		druidPluginScm1.setMaxPoolPreparedStatementPerConnectionSize(50); //
		me.add(druidPluginScm1);
		
		ActiveRecordPlugin arpScm1 = new ActiveRecordPlugin(Const.SCM, druidPluginScm1);
		_MappingKitScm1.mapping(arpScm1);
		me.add(arpScm1);
		
		arpScm1.addSqlTemplate("/sql/scm/_all_sqls_scm.sql"); //scm销售明细
		arpScm1.setShowSql(p.getBoolean("showSql", true));
		
	}


	/**
	 * 配置过滤器
	 */
	@Override
	public void configInterceptor(Interceptors me) {
		//配置全局跨域拦截器
		me.add(new CORSInterceptor());  //在需要支持跨域的 Action 方法或Controller中添加 @EnableCORS，
		
		//配置全局异常拦截器
		if(p.getBoolean("openException", true)) {
			me.add(new ExceptionInterceptor());
		}
		
	}

	/**
	 * 配置处理器
	 */
	@Override
	public void configHandler(Handlers me) {
		me.add(DruidKit.getDruidStatViewHandler()); // druid 统计页面功能
	}
	
	// 获得某天最大时间 2020-02-19 23:59:59
    public static Date getEndOfDay(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
        LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
        return Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());
    }

    // 获得某天最小时间 2020-02-17 00:00:00
    public static Date getStartOfDay(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
        LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);
        return Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant());
    }

	/**
	 * 程序启用后调用
	 */
	@Override
	public void onStart() {

		//启用定时任务
		if(p.getBoolean("openCorn", false) ) {
			ScmJobService job = new ScmJobService();
			//初始化定时任务
			job.init();
		}

		// 创建 IdGeneratorOptions 对象，请在构造函数中输入 WorkerId：
		IdGeneratorOptions options = new IdGeneratorOptions((short) 1);
		// options.WorkerIdBitLength = 10; // WorkerIdBitLength 默认值6，支持的 WorkerId 最大值为2^6-1，若 WorkerId 超过64，可设置更大的 WorkerIdBitLength
		// ...... 其它参数设置参考 IdGeneratorOptions 定义，一般来说，只要再设置 WorkerIdBitLength （决定 WorkerId 的最大值）。

		// 保存参数（必须的操作，否则以上设置都不能生效）：
		YitIdHelper.setIdGenerator(options);
		// 以上初始化过程只需全局一次，且必须在第2步之前设置。
		
		
//		SysCronService sysCron = new SysCronService();
//		
//		// 定时清除过期session和过期日志（每天0点 0 0 0 * * ?）  
//		CronUtil.schedule(p.get("sysCron.deleteSession"), new Task() {
//		    @Override
//		    public void execute() {
//		    	System.out.println("-定时任务-清除过期session。");
//		    	sysCron.deleteSession();
//		    	System.out.println("-定时任务-清除过期日志。");
//		    	sysCron.deleteLoginRecord();
//		    }
//		});
//		
//		
//		// 支持秒级别定时任务
//		CronUtil.setMatchSecond(true);
//		CronUtil.start(); //CronUtil.start(true); 表示守护线程模式运行。即执行的作业同定时任务线程同时结束，可以将定时任务设为守护线程，需要注意的是，此模式下会在调用stop时立即结束所有作业线程，请确保你的作业可以被中断。
//		
	}
	
	/**
	 * 程序停止前调用
	 */
	public void onStop() {
		//关闭定时任务
		if(p.getBoolean("openCorn", false) ) {
			CronUtil.stop(); 
		}
		
		try {
			//关闭数据连接
			DbKit.getConfig(Const.SCMDB).getConnection().close();
			//移除数据库连接
			DbKit.removeConfig(Const.SCMDB); 
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	

	
}
